package com.ruoyi.system.controlserver;

import com.alibaba.fastjson2.JSONObject;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @author chenjy
 * @date 2024/12/4 16:31
 **/
public class AndroidClient {
    private static final Logger log = LoggerFactory.getLogger(AndroidClient.class);
    private Channel channel;
    private int currentServerNo;

    public static void main(String[] args) throws InterruptedException {
        AndroidClient androidClient = new AndroidClient();
        androidClient.connect();
        androidClient.validChannel();
        TimeUnit.SECONDS.sleep(Integer.MAX_VALUE);
    }

    private void validChannel() {
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        Runnable task = () -> {
            if (!channel.isActive()) {
                log.warn("与服务器的连接断开，即将重新连接");
                try {
                    connect();
                } catch (Exception e) {
                    log.error("连接服务器发生异常", e);
                }
            }
        };
        executorService.scheduleWithFixedDelay(task, 5, 5, TimeUnit.SECONDS);
    }

    /**
     * 选择一个服务器连接地址
     * eg:
     * JSONObject defaultServer = new JSONObject();
     * defaultServer.put("ip", "127.0.0.1");
     * defaultServer.put("port", 9900);
     *
     * @return json
     */
    private JSONObject selectServerInfo() {
        // 查询服务器的ip地址列表
        List<JSONObject> list = loadServerIp();
        if (!list.isEmpty()) {
            currentServerNo = Math.min(currentServerNo, list.size());
            JSONObject serverInfo = list.get(currentServerNo);
            currentServerNo++;
            if (currentServerNo == list.size()) {
                currentServerNo = 0;
            }
            return serverInfo;
        }
        JSONObject defaultServer = new JSONObject();
        defaultServer.put("ip", "127.0.0.1");
        defaultServer.put("port", 9900);
        return defaultServer;
    }

    /**
     * 保存服务器信息
     *
     * @param serverInfo 服务器信息
     */
    private void addServerInfo(JSONObject serverInfo) {
        // TODO: 2024/12/5 执行保存
    }

    /**
     * 查询服务器列表
     *
     * @return list
     */
    private List<JSONObject> loadServerIp() {
        List<JSONObject> list = new ArrayList<>();
        // TODO: 2024/12/5 执行真正的查询

        JSONObject jsonObject1 = new JSONObject();
        jsonObject1.put("ip", "192.168.156.53");
        jsonObject1.put("port", 9900);
        JSONObject jsonObject2 = new JSONObject();
        jsonObject2.put("ip", "127.0.0.1");
        jsonObject2.put("port", 9900);

        list.add(jsonObject1);
        list.add(jsonObject2);
        return list;
    }

    private void connect() {
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        JSONObject serverInfo = selectServerInfo();
        String ip = serverInfo.getString("ip");
        int port = serverInfo.getInteger("port");
        log.info("当前连接的服务器地址：{}:{}", ip, port);
        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) {
                            ch.pipeline().addLast(new StringDecoder());
                            ch.pipeline().addLast(new StringEncoder());
                            ch.pipeline().addLast(new IdleStateHandler(5, 5, 10) {
                                @Override
                                protected void channelIdle(ChannelHandlerContext ctx, IdleStateEvent evt) {
                                    // 10秒内无读无写，主动上报自身状态
                                    if (evt.state() == IdleState.ALL_IDLE) {
                                        // 查询自身状态
                                        String jsonStatus = querySmartStatus();
                                        // 发送自身状态
                                        ctx.writeAndFlush(jsonStatus).addListener(future -> {
                                            if (future.isSuccess()) {
                                                log.info("自身状态定时发送成功:{}", jsonStatus);
                                                return;
                                            }
                                            log.error("自身状态定时发送失败", future.cause());
                                        });
                                    }
                                }
                            });
                            ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
                                @Override
                                public void channelActive(ChannelHandlerContext ctx) {
                                    final SocketAddress socketAddress = ctx.channel().remoteAddress();
                                    InetSocketAddress address = (InetSocketAddress) socketAddress;
                                    log.info("连接建立,{}", address);
                                    // 查询自身状态
                                    String jsonStatus = querySmartStatus();
                                    // 发送自身状态
                                    ctx.writeAndFlush(jsonStatus).addListener(future -> {
                                        if (future.isSuccess()) {
                                            log.info("自身状态发送成功:{}", jsonStatus);
                                            return;
                                        }
                                        log.error("自身状态发送失败", future.cause());
                                    });
                                }

                                @Override
                                public void channelRead(ChannelHandlerContext ctx, Object msg) {
                                    log.info("得到服务端指令:{}", msg.getClass());
                                    if (msg instanceof String) {
                                        String info = (String) msg;
                                        log.info("服务端指令内容：{}", info);
                                        final String answer = "answer--";
                                        try {
                                            // 执行指令
                                            String result = executeInstruction(info);
                                            ctx.writeAndFlush(result).addListener(future -> {
                                                if (future.isSuccess()) {
                                                    log.info("指令 {} 执行结果返回成功", info);
                                                    return;
                                                }
                                                log.error("指令 {} 执行结果返回失败", info, future.cause());
                                            });
                                            return;
                                        } catch (Exception ex) {
                                            log.error("指令解析失败", ex);
                                            String dataPacket = answer.concat("instruct--指令解析失败");
                                            ctx.writeAndFlush(dataPacket).addListener(future -> {
                                                if (future.isSuccess()) {
                                                    log.info("指令 {} 解析失败提示返回成功", info);
                                                    return;
                                                }
                                                log.error("指令 {} 解析失败提示返回失败", info, future.cause());
                                            });
                                        }
                                        log.error("客户端收到未定义的数据格式:{}", info);
                                        return;
                                    }
                                    log.error("客户端收到未预期的数据类型");
                                }

                                @Override
                                public void channelInactive(ChannelHandlerContext ctx) {
                                    log.info("与服务器 {} 连接断开", ctx.channel().remoteAddress());
                                }

                                @Override
                                public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                                    log.info("客户端发生了异常或者服务器 {} 关闭了链接", ctx.channel().remoteAddress());
                                    super.exceptionCaught(ctx, cause);
                                }
                            });
                        }
                    });
            ChannelFuture f = b.connect(ip, port).sync();
            if (f.isSuccess()) {
                channel = f.channel();
                log.info("与服务器连接建立成功 {}", f.channel().id().asShortText());
                return;
            }
            log.error("与服务器连接建立失败");
        } catch (Exception e) {
            log.error("与服务器连接建立异常!", e);
        }
    }

    /**
     * 执行指令
     * eg:screen:on
     * 指令回馈,回馈示例：answer--screen:on--success
     *
     * @param info 指令内容
     * @return 解析
     */
    private String executeInstruction(String info) {
        String answer = "answer--";
        // 验证是否是保存服务器地址指令 serverInfo:ip:port
        String serverInfo = "serverInfo:";
        String success = "success";
        if (info.startsWith(serverInfo)) {
            String serverInfoStr = info.substring(serverInfo.length());
            JSONObject serverJson = new JSONObject();
            String[] array = serverInfoStr.split(":");
            serverJson.put("ip", array[0]);
            serverJson.put("port", Integer.parseInt(array[1]));
            addServerInfo(serverJson);
            return answer.concat(serverInfoStr).concat(success);
        }
        // TODO: 2024/12/4 解析指令并执行
        return answer.concat(info).concat(success);
    }

    /**
     * 查询自身状态，返回json string
     * 如果查询某个状态发生失败或者异常，回传默认值
     *
     * @return json string
     */
    private String querySmartStatus() {
        JSONObject jsonStatus = new JSONObject();
        // 查询屏幕状态
        boolean screenStatus = queryScreenStatus();
        jsonStatus.put("screenStatus", screenStatus);
        // 查询信号源
        String source = querySource();
        jsonStatus.put("source", source);
        // 查询音量
        int voice = queryVoice();
        jsonStatus.put("voice", voice);
        // 查询ops状态
        boolean opsStatus = queryOpsStatus();
        jsonStatus.put("opsStatus", opsStatus);
        // 查询静音状态
        boolean muteStatus = queryMuteStatus();
        jsonStatus.put("muteStatus", muteStatus);
        String notice = "notice--";
        return notice.concat(jsonStatus.toJSONString());
    }

    private boolean queryMuteStatus() {
        // TODO: 2024/12/4   执行查询操作
        return false;
    }

    private boolean queryOpsStatus() {
        // TODO: 2024/12/4   执行查询操作
        return false;
    }

    private int queryVoice() {
        // TODO: 2024/12/4   执行查询操作
        return 0;
    }

    private String querySource() {
        // TODO: 2024/12/4   执行查询操作
        return "VGA1";
    }

    private boolean queryScreenStatus() {
        // TODO: 2024/12/4   执行查询操作
        return true;
    }
}
